ホームに戻る
出典 :
Model-View-ViewModel - .NET | Microsoft Learn INotifyPropertyChanged インターフェイス (System.ComponentModel) | Microsoft Learn ICommand インターフェイス (System.Windows.Input) | Microsoft Learn MVVMパターンの常識 ― 「M」「V」「VM」の役割とは? - @IT WPF超絶入門から学び直し1【MVVM】 #C# - Qiita MVVMパターンを使用したWPFにおける View - ViewModel の連携について #C# - Qiita 【C#-WPF】MVVMパターンにおけるViewとViewModel間のインスタンス生成方法について - 業務のためのC#・C言語・C++学習
関連 :
INotifyPropertyChanged コマンド(ICommand) MVVM Toolkit データバインディング ReactiveProperty 依存関係プロパティ デリゲートとイベント
目次 :

MVVMパターンとは

WPFで推奨されているデザインパターンで、Model - View - ViewModel の略。 外観( View )と、外観に関連づくデータモデル( ViewModel )を分離することで、堅牢で透過性の高いアプリケーションとすることを目論んでいる。

MVCとの関連

MVVMは、Webアプリで主に用いられるMVC( Model - View - Controler )から派生したパターンで、類似点も多い。 View が外観を、Model が外観に直接関連しないデータを取り扱うという点は共通である。

MVVMの構成

画像 View はXAMLとコードビハインド(XAML.CS)から成り、外観を司る。 ViewModel は View とは独立しており、ViewModel のインスタンスが View の DataContext として関連づけられる。 これにより ViewModel のプロパティ(CLIプロパティ)と View の依存関係プロパティとが関連づけられ、 ViewModel の変更が View に伝播する。 この View と関連づけられた ViewModel のプロパティを「変更通知プロパティ」と呼び、 View と ViewModel とのプロパティの関連づけを「データバインディング」と呼ぶ。 逆に View に対するユーザの操作(イベント)は ViewModel の「コマンド」に関連づけられ、ユーザ操作が ViewModel に伝播する。 (コマンドバインディング) Model ( ViewModel ではない)は外観によらないデータおよび業務ロジックを指し、ViewModel に組み込まれることで外観に関連づけられる。

ファイル構成例

画像 ウィンドウまたはユーザーコントロールごとに View と ViewModel を作成する。 View と連動させる ViewModel のプロパティは組み込み型を直接保持するか、必要な Model をインスタンス化する。 コマンドも同様に、それぞれの View で用いるもののインスタンスを ViewModel で保持する。

注意が必要な点

Visual Studioでウィンドウやユーザーコントロールを作成した際、対応するXAMLとコードビハインドは対で作成されるが、 ViewModel はいかなる場合も自動では作成されない(MVVMに準拠した構成とならない)。 このため、コードビハインドが ViewModel だと誤解されることも多いが誤りである。ViewModel はあくまで手動で作成する必要がある。 なお、MVVMパターンはコードビハインドの記述を最小限に留めることが推奨されている。 DataContextやバインディングの指定はXAMLで行うことが可能で、ユーザアクションへの対応(イベント処理)もコマンドに委譲できる。 この場合、コードビハインドにはコンストラクタしか記述されない。

ViewModel の実装

ViewModel のプロパティ変化を View に通知 : 変更通知プロパティ

ViewModel で保持している情報が変化した際に View 側で何らかの動作を起こしたい(例えば、UIの表示を変更する)場合は、 ViewModel にINotifyPropertyChangedインタフェースを実装したうえでPropertyChangedイベントを発生させる。 View 側はPropertyChangedイベントフックに、イベント発生時にコールしたいコールバック(イベントハンドラ)を登録する。 View 側のデータバインディングされたプロパティ(ターゲット)も PropertyChanged を契機として変化するため、INotifyPropertyChanged を実装しなければ連動しない。 (即ち、ViewModel と View の両方にINotifyPropertyChangedを実装する必要がある。 ただし、ターゲットに指定されるコントロールの依存関係プロパティは通常INotifyPropertyChangedを実装しているため、特殊な操作は必要ない。) 詳細はリンク先を参照。

View の操作を ViewModel に通知 : コマンド

UIへの操作を ViewModel に伝えたい場合はコマンドを使用する。詳細はリンク先を参照。

View と ViewModel の結合

任意のクラスを ViewModel として新たに作成し、View のDataContextに設定する。
ViewModel : MainViewModel.cs
namespace Sample { // ViewModel の本体 class MainViewModel { // プロパティ public string Message { get; set; } = "サンプルメッセージ"; } }
View : MainWindow.xaml
<Window (略) > <!-- MainViewModel を DataContext に設定 --> <Window.DataContext> <local:MainViewModel /> </Window.DataContext> : <!-- TextBlock.Text を DataContext ( MainViewModel )の Message とバインド --> <TextBlock Text="{Binding Message}" />
ここではMainViewModelWindowDataContextとして設定している。 なおlocalMainViewModelが属する名前空間(Sample)のエイリアスである。 MainViewModelMessageプロパティをTextBlockTextへとデータバインディングを行っているが、 MainViewModelDataContextとして関連づけているため、プロパティ名(Message)のみを記述すればよい。 (MainViewModel.Messageなどとする必要は無い。詳細はデータバインディングを参照。)
View : MainWindow.xaml.cs
namespace Sample { public partial class MainWindow : Window { // コンストラクタ public MainWindow() { InitializeComponent(); this.DataContext = new MainViewModel(); } } }
DataContextの指定はコードビハインドから行うことも可能(推奨されない)。 その場合はコンストラクタ中で ViewModel のインスタンスをDataContextに代入する。

注意が必要な点

XAMLからDataContextの指定を行う場合、呼び出せる ViewModel のコンストラクタはデフォルトコンストラクタ(引数の無いコンストラクタ)に限定される。 このため、デフォルトコンストラクタ以外を呼びたい場合はコードビハインドで指定を行うなど回避策をとる必要がある。

ViewModel 構築の支援

変更通知プロパティやコマンドを含めた ViewModel の実装は煩雑であるが、 ViewModel の構築を支援してくれるライブラリが複数存在し、それらを活用することでコードの記述を大幅に削減できる。 ReactivePropertyが代表的。詳細はリンク先を参照。